/**
 *FilePropertyDialog.java
 *@anthor Daniel Liu
 *2006-4-28 5:37:35
 **/
package lex.explorer.file;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.text.DateFormat;
import java.util.Stack;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.*;
import javax.swing.filechooser.FileView;

import org.lex.explorer.file.PropertiesDialog;
import org.lex.io.filesystem.FileSystem;
import org.lex.swing.widgets.EnhancedDialog;
import org.lex.utils.MyTimer;
import org.lex.utils.Pair;
import org.lex.utils.text.DateTimeUtilities;
import org.lex.utils.text.SizeFormat;



/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
public class PropertiesDialog extends EnhancedDialog
{
	private static ExecutorService pool = null;
	private static int updateInterval = 500;
	static
	{
		// ��ʼ������Ŀ¼��С������̳߳�
		pool = Executors.newCachedThreadPool();
	}
	private JButton applyButton = null;
	private JLabel attributeLabel = null;
	private JPanel attributePanel = null;
	private JPanel buttonsPanel = null;
	private JButton cancelButton = null;
	private JTextField fileNameTextField = null;
	private JPanel gluePane = null;
	private JCheckBox hidenCheckBox = null;
	private JLabel iconLabel = null;
	private JLabel locationLabel = null;
	private JTextField locationTextField = null;
	private JLabel modifiedLabel = null;
	private JTextField modifiedTextField = null;
	private JButton okButton = null;
	private JPanel pane = null;
	private JCheckBox readOnlyCheckBox = null;
	private JLabel sizeLabel = null;
	private JTextField sizeTextField = null;
	private JButton touchButton = null;
	private JLabel typeLabel = null;
	private JTextField typeTextField = null;
	private JLabel containsLabel = null;
	private JTextField containsTextField = null;
	private JSeparator bottomSeparator;
	private JSeparator topSeparator;
	private FileView view = null;
	private MyTimer timer = null;
	private SizeCounter sizeCounter = null;

	public PropertiesDialog( Window root )
	{
		super( root );
		this.view = FileSystem.getLocalFileView();
		initialize();
		timer = new MyTimer( updateInterval ){
			@Override
			public void actionPerformed( ActionEvent e )
			{
				sizeTextField.setText( SizeFormat.autoFormat( sizeCounter.size ) + " ("
						+ sizeCounter.size + " bytes)" );
				containsTextField.setText( sizeCounter.files + " files, " + sizeCounter.folders
						+ " folders" );
			}
		};
	}

	public static void showFiles( Window root, File[] files )
	{
		if( null == files || 0 == files.length )
			return;
		PropertiesDialog d = new PropertiesDialog( root );
		d.setSize( 330, 370 );
		d.setLocationRelativeTo( root );
		if( 1 == files.length )
			d.showFile( files[0] );
		else
			d.showFile( files );
	}

	public void ok()
	{
		this.apply();
		this.dispose();
	}

	@Override
	public void cancel()
	{
		this.dispose();
	}

	public void apply()
	{}

	public void showFile( File file )
	{
		this.setTitle( file.getName() + " Properties" );
		this.iconLabel.setIcon( view.getIcon( file ) );
		this.fileNameTextField.setText( view.getName( file ) );
		this.typeTextField.setText( view.getTypeDescription( file ) );
		this.locationTextField.setText( file.getParent() );
		this.modifiedTextField.setText( DateTimeUtilities.formatDateTime( file.lastModified(),
			DateFormat.LONG ) );
		this.readOnlyCheckBox.setSelected( !file.canWrite() );
		this.hidenCheckBox.setSelected( file.isHidden() );
		if( true == file.isDirectory() )
		{
			Stack<File> files = new Stack<File>();
			files.push( file );
			sizeCounter = new SizeCounter( files );
			pool.execute( sizeCounter );
		}
		else
		{
			sizeTextField.setText( SizeFormat.autoFormat( file.length() ) + " (" + file.length()
					+ " bytes)" );
		}
		this.setVisible( true );
	}

	public void showFile( File[] files )
	{
		this.setTitle( files[0].getName() + "... Properties" );
		this.iconLabel.setIcon( view.getIcon( files[0] ) );
		Pair<Stack<File>, Pair<String, Long>> count = this.count( files );
		int foldersNumber = count.first().size();
		this.fileNameTextField.setText( (files.length - foldersNumber) + " files, " + foldersNumber
				+ " folders" );
		this.typeTextField.setText( count.second().first() );
		this.locationTextField.setText( files[0].getParent() );
		if( 0 == foldersNumber )
		{
			// selected are files
			this.sizeTextField.setText( SizeFormat.autoFormat( count.second().second() ) + " ("
					+ count.second().second() + " bytes)" );
			this.containsTextField.setText( files.length + " files, 0 folders" );
		}
		else
		{
			// selected all are folders, no file selected
			sizeCounter = new SizeCounter( count.first() );
			pool.execute( sizeCounter );
		}
		this.modifiedTextField.setText( "" );
		this.readOnlyCheckBox.setSelected( !files[0].canWrite() );
		this.hidenCheckBox.setSelected( files[0].isHidden() );
		this.setVisible( true );
	}

	/**
	 * �����ӿ�
	 */
	void clean()
	{
		this.setTitle( "" );
		this.iconLabel.setIcon( null );
		this.fileNameTextField.setText( "" );
		this.typeTextField.setText( "" );
		this.locationTextField.setText( "" );
		this.sizeTextField.setText( "" );
		this.modifiedTextField.setText( "" );
		this.readOnlyCheckBox.setSelected( false );
		this.hidenCheckBox.setSelected( false );
	}

	private Pair<Stack<File>, Pair<String, Long>> count( File[] files )
	{
		boolean singleType = true;
		long size = 0L;
		String type = view.getTypeDescription( files[0] );
		Stack<File> folders = new Stack<File>();
		for( File file : files )
		{
			if( true == file.isDirectory() )
				folders.push( file );
			else
				size += file.length();
			if( false == view.getTypeDescription( file ).equals( type ) )
				singleType = false;
		}
		if( true == singleType )
			type = "All of type " + type;
		else
			type = "Multiple Types";
		return new Pair<Stack<File>, Pair<String, Long>>( folders, new Pair<String, Long>( type,
			size ) );
	}

	/**
	 * ����GUI
	 */
	private void initialize()
	{
		this.setSize( 300, 345 );
		this.setContentPane( getPane() );
	}

	private JPanel getPane()
	{
		if( pane == null )
		{
			containsLabel = new JLabel();
			containsLabel.setText( "Contains:" );
			attributeLabel = new JLabel();
			attributeLabel.setText( "Attribute:" );
			modifiedLabel = new JLabel();
			modifiedLabel.setText( "Modified:" );
			sizeLabel = new JLabel();
			sizeLabel.setText( "Size:" );
			locationLabel = new JLabel();
			locationLabel.setText( "Location:" );
			typeLabel = new JLabel();
			typeLabel.setText( "Type:" );
			iconLabel = new JLabel();
			iconLabel.setText( "" );
			iconLabel.setHorizontalAlignment( javax.swing.SwingConstants.CENTER );
			iconLabel.setHorizontalTextPosition( javax.swing.SwingConstants.CENTER );
			iconLabel.setIcon( new ImageIcon( getClass().getResource(
				"/lex/resources/images/refresh.png" ) ) );
			pane = new JPanel();
			GridBagLayout paneLayout = new GridBagLayout();
			pane.setLayout( paneLayout );
			pane
				.add( iconLabel, new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0,
					GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 12, 11, 5, 0 ),
					0, 0 ) );
			pane.add( getFileNameTextField(), new GridBagConstraints( 1, 0, 2, 1, 1.0, 0.0,
				GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
				new Insets( 12, 5, 5, 12 ), 0, 0 ) );
			pane
				.add( typeLabel, new GridBagConstraints( 0, 2, 1, 1, 0.0, 0.0,
					GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 5, 11, 0, 0 ), 0,
					0 ) );
			pane.add( getTypeTextField(), new GridBagConstraints( 1, 2, 2, 1, 1.0, 0.0,
				GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 12 ),
				0, 0 ) );
			pane
				.add( locationLabel, new GridBagConstraints( 0, 3, 1, 1, 0.0, 0.0,
					GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 5, 11, 5, 0 ), 0,
					0 ) );
			pane.add( getLocationTextField(), new GridBagConstraints( 1, 3, 2, 1, 1.0, 0.0,
				GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 12 ),
				0, 0 ) );
			pane
				.add( sizeLabel, new GridBagConstraints( 0, 4, 1, 1, 0.0, 0.0,
					GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 5, 11, 5, 0 ), 0,
					0 ) );
			pane.add( getSizeTextField(), new GridBagConstraints( 1, 4, 2, 1, 1.0, 0.0,
				GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 0, 12 ),
				0, 0 ) );
			pane
				.add( modifiedLabel, new GridBagConstraints( 0, 6, 1, 1, 0.0, 0.0,
					GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 5, 11, 5, 0 ), 0,
					0 ) );
			pane.add( getModifiedTextField(), new GridBagConstraints( 1, 6, 1, 1, 10.0, 0.0,
				GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets( 5, 5, 5, 0 ),
				0, 0 ) );
			pane
				.add( attributeLabel, new GridBagConstraints( 0, 8, 1, 1, 0.0, 0.0,
					GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 5, 11, 5, 0 ), 0,
					0 ) );
			pane
				.add( getTouchButton(), new GridBagConstraints( 2, 6, 1, 1, 0.0, 0.0,
					GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets( 5, 5, 5, 12 ), 0,
					0 ) );
			pane.add( getAttributePanel(), new GridBagConstraints( 1, 8, 2, 1, 1.0, 0.0,
				GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
				new Insets( 5, 0, 5, 12 ), 0, 0 ) );
			pane
				.add( getGluePane(), new GridBagConstraints( 0, 9, 3, 1, 10.0, 10.0,
					GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets( 0, 0, 0, 0 ),
					0, 0 ) );
			pane.add(getButtonsPanel(), new GridBagConstraints(0, 10, 3, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 12, 6), 0, 0));
			pane
				.add( containsLabel, new GridBagConstraints( 0, 5, 1, 1, 0.0, 0.0,
					GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 5, 11, 5, 0 ), 0,
					0 ) );
			pane.add( getContainsTextField(), new GridBagConstraints( 1, 5, 2, 1, 1.0, 0.0,
				GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
				new Insets( 5, 5, 0, 12 ), 0, 0 ) );
			pane.add( getTopSeparator(), new GridBagConstraints( 0, 1, 3, 1, 10.0, 0.0,
				GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
				new Insets( 5, 11, 6, 12 ), 0, 0 ) );
			pane.add(getBottomSeparator(), new GridBagConstraints(0, 7, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 11, 5, 12), 0, 0));
		}
		return pane;
	}

	private JTextField getTypeTextField()
	{
		if( typeTextField == null )
		{
			typeTextField = new JTextField();
			typeTextField.setEditable( false );
			typeTextField.setText( "type" );
			typeTextField.setEnabled( true );
		}
		return typeTextField;
	}

	private JTextField getFileNameTextField()
	{
		if( fileNameTextField == null )
		{
			fileNameTextField = new JTextField();
			fileNameTextField.setText( "file name" );
		}
		return fileNameTextField;
	}

	private JTextField getLocationTextField()
	{
		if( locationTextField == null )
		{
			locationTextField = new JTextField();
			locationTextField.setEditable( false );
		}
		return locationTextField;
	}

	private JTextField getSizeTextField()
	{
		if( sizeTextField == null )
		{
			sizeTextField = new JTextField();
			sizeTextField.setText( "1.32GB( 130,682,112 bytes)" );
			sizeTextField.setEditable( false );
		}
		return sizeTextField;
	}

	private JTextField getContainsTextField()
	{
		if( containsTextField == null )
		{
			containsTextField = new JTextField();
			containsTextField.setEditable( false );
			containsTextField.setText( "1 File" );
		}
		return containsTextField;
	}

	private JTextField getModifiedTextField()
	{
		if( modifiedTextField == null )
		{
			modifiedTextField = new JTextField();
			modifiedTextField.setEditable( false );
			modifiedTextField.setText( "modified" );
		}
		return modifiedTextField;
	}

	private JButton getTouchButton()
	{
		if( touchButton == null )
		{
			touchButton = new JButton();
			touchButton.setText( "" );
			touchButton.setIcon( new ImageIcon( getClass().getResource(
				"/lex/resources/images/refresh.png" ) ) );
			touchButton.setToolTipText( "Touch" );
			touchButton.setPreferredSize( new java.awt.Dimension( 22, 22 ) );
			touchButton.setMaximumSize( new java.awt.Dimension( 22, 22 ) );
		}
		return touchButton;
	}

	private JPanel getAttributePanel()
	{
		if( attributePanel == null )
		{
			FlowLayout flowLayout = new FlowLayout();
			flowLayout.setAlignment( FlowLayout.LEFT );
			flowLayout.setAlignOnBaseline( true );
			flowLayout.setVgap( 0 );
			attributePanel = new JPanel();
			attributePanel.setLayout( flowLayout );
			attributePanel.add( getReadOnlyCheckBox(), null );
			attributePanel.add( getHidenCheckBox(), null );
		}
		return attributePanel;
	}

	private JCheckBox getReadOnlyCheckBox()
	{
		if( readOnlyCheckBox == null )
		{
			readOnlyCheckBox = new JCheckBox();
			readOnlyCheckBox.setText( "Read Only" );
		}
		return readOnlyCheckBox;
	}

	private JCheckBox getHidenCheckBox()
	{
		if( hidenCheckBox == null )
		{
			hidenCheckBox = new JCheckBox();
			hidenCheckBox.setText( "Hidden" );
			hidenCheckBox.setSelected( true );
			hidenCheckBox.setEnabled( false );
		}
		return hidenCheckBox;
	}

	private JPanel getGluePane()
	{
		if( gluePane == null )
		{
			gluePane = new JPanel();
		}
		return gluePane;
	}

	private JPanel getButtonsPanel()
	{
		if( buttonsPanel == null )
		{
			buttonsPanel = new JPanel();
			FlowLayout buttonsPanelLayout = new FlowLayout();
			buttonsPanelLayout.setAlignOnBaseline( true );
			buttonsPanelLayout.setAlignment( FlowLayout.RIGHT );
			buttonsPanelLayout.setVgap( 0 );
			buttonsPanel.setLayout( buttonsPanelLayout );
			buttonsPanel.add( getOkButton() );
			buttonsPanel.add( getCancelButton() );
			buttonsPanel.add( getApplyButton() );
		}
		return buttonsPanel;
	}

	private JButton getOkButton()
	{
		if( okButton == null )
		{
			okButton = new JButton();
			okButton.setText( "OK" );
			okButton.addActionListener( new ActionListener(){
				public void actionPerformed( ActionEvent e )
				{
					ok();
				}
			} );
		}
		return okButton;
	}

	private JButton getApplyButton()
	{
		if( applyButton == null )
		{
			applyButton = new JButton();
			applyButton.setText( "Apply" );
			applyButton.setEnabled( false );
			applyButton.addActionListener( new ActionListener(){
				public void actionPerformed( ActionEvent e )
				{
					apply();
				}
			} );
		}
		return applyButton;
	}

	private JButton getCancelButton()
	{
		if( cancelButton == null )
		{
			cancelButton = new JButton();
			cancelButton.setText( "Cancel" );
			cancelButton.addActionListener( new ActionListener(){
				public void actionPerformed( ActionEvent e )
				{
					cancel();
				}
			} );
		}
		return cancelButton;
	}

	private JSeparator getTopSeparator()
	{
		if( topSeparator == null )
		{
			topSeparator = new JSeparator();
		}
		return topSeparator;
	}

	private JSeparator getBottomSeparator()
	{
		if( bottomSeparator == null )
		{
			bottomSeparator = new JSeparator();
		}
		return bottomSeparator;
	}

	class SizeCounter implements Runnable
	{
		private int folders = 0;
		private int files = 0;
		private long size = 0L;
		private boolean isCancelled = false;
		private Stack<File> queue = null;

		SizeCounter( Stack<File> files )
		{
			this.queue = files;
		}

		public void cancel()
		{
			this.isCancelled = true;
		}

		public void run()
		{
			timer.start();
			while( false == Thread.currentThread().isInterrupted() && false == isCancelled
					&& false == queue.isEmpty() )
			{
				File file = queue.pop();
				File[] children = file.listFiles();
				if( null == children )
					break;
				for( File child : children )
				{
					if( true == child.isDirectory() )
					{
						queue.push( child );
						folders++;
					}
					else
					{
						files++;
						size += child.length();
					}
				}
			}
			timer.actionPerformed( null );
			timer.stop();
		}
	}
}
